package in.muton.edushare.pages.common;

import in.muton.edushare.helper.TinyMCEHelper;
import in.muton.edushare.pages.EduShareBasePage;
import in.muton.edushare.processing.objects.CourseDataHandler;
import in.muton.edushare.processing.objects.UnivDataHandler;
import in.muton.edushare.wicket.converters.choicerenderers.GenericRenderer;
import in.muton.edushare.wicket.models.CayenneList;

import java.util.HashMap;
import java.util.List;

import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.Radio;
import org.apache.wicket.markup.html.form.RadioGroup;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
import org.apache.wicket.model.PropertyModel;

import com.edushare.common.dao.CoursesDAO;
import com.edushare.common.util.StringUtil;
import com.edushare.common.vo.Courses;
import com.edushare.common.vo.PrerequisiteLink;
import com.edushare.common.vo.Universities;

public class CourseProfile extends EdusharePanel {

	public CourseProfile(String id, IModel<Courses> model, EduShareBasePage page) {
		super(id, page);
		this.courseModel = model;
		final GenericRenderer<Integer> gr = new GenericRenderer<Integer>(
				getCoursesList(), null);
		Form<Void> f = new Form<Void>("form1") {
			@Override
			public void onSubmit() {
				Integer courseId = gr.getSelection();
				if (courseId != null) {
					Courses c = new CoursesDAO(getORMInterface())
							.getCourseById(courseId);
					if (c != null)
						new CoursesDAO(getORMInterface()).addPrereqToCourse(
								courseModel.getObject(), c);
				}

				if (!StringUtil
						.isValid(courseModel.getObject().getCourseName())) {
					setError("Course name is required");
					return;
				}
				Courses c = new CoursesDAO(getORMInterface())
						.checkCourseUniqueness(courseModel.getObject());
				if (c != null) {
					setError("A course " + c.getCourseName()
							+ " is already present with the "
							+ "given course code. Please choose a different course code.");
					return;
				}
				if (error) {
					error = false;
					return;
				}
				clearError();
				getORMInterface().commitAllChanges();
			}
			private static final long serialVersionUID = -889820277693100914L;
		};
		add(f);
		f.add(new TextField<String>("courseNameEdit",
				new PropertyModel<String>(courseModel, "courseName")));
		f.add(new TextField<String>("courseCode", new PropertyModel<String>(
				courseModel, "courseCode")));
		f.add(new TextArea<String>("courseDescEdit", new PropertyModel<String>(
				courseModel, "courseDesc")).add(TinyMCEHelper
				.getDefaultTinyMCEBehavior()));
		f.add(new TextField<String>("lectureHoursEdit",
				new PropertyModel<String>(this, "lectureHoursEdit")));
		f.add(new TextField<String>("tutorialHoursEdit",
				new PropertyModel<String>(this, "tutorialHoursEdit")));
		f.add(new TextField<String>("labHoursEdit", new PropertyModel<String>(
				this, "labHoursEdit")));
		f.add(new TextField<String>("creditsEdit", new PropertyModel<String>(
				this, "creditsEdit")));
		f.add(new TextField<String>("strengthEdit", new PropertyModel<String>(
				this, "strengthEdit")));

		WebMarkupContainer wmc;
		f.add(wmc = new WebMarkupContainer("prereqList") {
			private static final long serialVersionUID = 300996677683699875L;

			@Override
			public boolean isVisible() {
				if (courseModel.getObject().getPrerequisiteLink().size() == 0)
					return false;
				return true;
			}
		});

		wmc.add(new Label("andOr", new Model<String>() {
			@Override
			public String getObject() {
				if (courseModel.getObject().getPrerequisitesCondition() == null) {
					courseModel.getObject().setPrerequisitesCondition(
							Courses.PREREQUISITE_COURSES_AND);
					getORMInterface().commitAllChanges();
				}
				if (courseModel.getObject().getPrerequisiteLink().size() < 2) {
					return "";
				}
				if (courseModel.getObject().getPrerequisitesCondition() == Courses.PREREQUISITE_COURSES_AND)
					return "All of these courses";
				else
					return "Any one of these courses";
			}

			private static final long serialVersionUID = -1341860182549424883L;
		}));

		wmc.add(new ListView<IModel<Courses>>("preReqs",
				new PrerequisiteCourses()) {
			@Override
			protected void populateItem(final ListItem<IModel<Courses>> arg0) {
				arg0.add(new Label("courseName", arg0.getModelObject()
						.getObject().getCourseName()));
				arg0.add(new Link<Void>("remove") {
					@Override
					public void onClick() {
						new CoursesDAO(getORMInterface()).removeCoursePrereq(
								courseModel.getObject(), arg0.getModelObject()
										.getObject());
					}

					private static final long serialVersionUID = 1584360225447471608L;
				});
			}

			private static final long serialVersionUID = 5472044629696448581L;
		});

		f.add(wmc = new WebMarkupContainer("multiplePrereqWmc") {
			private static final long serialVersionUID = 4189542554867544133L;

			@Override
			public boolean isVisible() {
				return (courseModel.getObject().getPrerequisiteLink().size() > 1);
			}
		});

		RadioGroup<Integer> rg = new RadioGroup<Integer>("radioGroup",
				new PropertyModel<Integer>(courseModel,
						"prerequisitesCondition"));
		wmc.add(rg);
		rg.add(new Radio<Integer>("and", new Model<Integer>(new Integer(
				Courses.PREREQUISITE_COURSES_AND))));
		rg.add(new Radio<Integer>("or", new Model<Integer>(new Integer(
				Courses.PREREQUISITE_COURSES_OR))));

		f.add(new DropDownChoice<String>("courseOptions", gr.getModel(), gr
				.getOptions(), gr));
		f.add(new Button("add") {

			@Override
			public void onSubmit() {
				Integer courseId = gr.getSelection();
				if (courseId != null) {
					Courses c = new CoursesDAO(getORMInterface())
							.getCourseById(courseId);
					if (c != null)
						new CoursesDAO(getORMInterface()).addPrereqToCourse(
								courseModel.getObject(), c);
				} else {
					setError("Please select a course");
				}
			}

			private static final long serialVersionUID = 6067209841417194104L;
		});
	}

	private class PrerequisiteCourses implements IModel<List<IModel<Courses>>> {
		public List<IModel<Courses>> getObject() {
			List<PrerequisiteLink> preList = courseModel.getObject()
					.getPrerequisiteLink();
			CayenneList<Courses> cl = new CayenneList<Courses>(null);
			for (PrerequisiteLink p : preList) {
				cl.add(p.getPrerequisite());
			}
			return cl.getObject();
		}

		public void setObject(List<IModel<Courses>> arg0) {
		}

		public void detach() {
		}

		private static final long serialVersionUID = 3488057713842710221L;
	}

	private HashMap<String, Integer> getCoursesList() {
		IModel<Universities> univ = new CourseDataHandler(courseModel, 0)
				.getOwnerUniv();
		List<IModel<Courses>> cList = new UnivDataHandler(univ).getCourses()
				.getObject();
		HashMap<String, Integer> hm = new HashMap<String, Integer>();

		List<Courses> preList = new CoursesDAO(getORMInterface())
				.getPrerequisites(courseModel.getObject());

		for (IModel<Courses> c : cList) {
			if (preList.contains(c.getObject())
					|| c.getObject() == courseModel.getObject())
				continue;
			hm.put(c.getObject().getCourseName(), c.getObject().getCourseId());
		}
		return hm;
	}

	public void setLectureHoursEdit(String s) {
		try {
			if (s.equals(UNAVAILABLE))
				return;
			int i = Integer.parseInt(s);
			courseModel.getObject().setLectureHours(i);
			if (i < 0)
				throw new NumberFormatException();
		} catch (NumberFormatException e) {
			error = true;
			setError("Class hours, class strength and "
					+ "course credits should be valid numbers.");
		}
	}

	public String getLectureHoursEdit() {
		if (courseModel.getObject().getLectureHours() == Courses.NOT_AVAILABLE)
			return UNAVAILABLE;
		return courseModel.getObject().getLectureHours().toString();
	}

	public void setTutorialHoursEdit(String s) {
		try {
			if (s.equals(UNAVAILABLE))
				return;
			int i = Integer.parseInt(s);
			courseModel.getObject().setTutorialHours(i);
			if (i < 0)
				throw new NumberFormatException();
		} catch (NumberFormatException e) {
			error = true;
			setError("Class hours, class strength and "
					+ "course credits should be valid numbers.");
		}
	}

	public String getTutorialHoursEdit() {
		if (courseModel.getObject().getTutorialHours() == Courses.NOT_AVAILABLE)
			return UNAVAILABLE;
		return courseModel.getObject().getTutorialHours().toString();
	}

	public void setLabHoursEdit(String s) {
		try {
			if (s.equals(UNAVAILABLE))
				return;
			int i = Integer.parseInt(s);
			courseModel.getObject().setPracticalHours(i);
			if (i < 0)
				throw new NumberFormatException();
		} catch (NumberFormatException e) {
			error = true;
			setError("Class hours, class strength and "
					+ "course credits should be valid numbers.");
		}
	}

	public String getLabHoursEdit() {
		if (courseModel.getObject().getPracticalHours() == Courses.NOT_AVAILABLE)
			return UNAVAILABLE;
		return courseModel.getObject().getPracticalHours().toString();
	}

	public String getCreditsEdit(){
		return courseModel.getObject().getCreditString();
	}
	
	public void setCreditsEdit(String s) {
		try {
			if (s.equals(UNAVAILABLE))
				return;
			int i = Integer.parseInt(s);
			courseModel.getObject().setCredits(i);
			if (i < 0)
				throw new NumberFormatException();
		} catch (NumberFormatException e) {
			error = true;
			setError("Class hours, class strength and "
					+ "course credits should be valid numbers.");
		}
	}

	public void setStrengthEdit(String s) {
		try {
			if (s.equals(UNAVAILABLE))
				return;
			int i = Integer.parseInt(s);
			courseModel.getObject().setStrength(i);
			if (i < 0)
				throw new NumberFormatException();
		} catch (NumberFormatException e) {
			error = true;
			setError("Class hours, class strength and "
					+ "course credits should be valid numbers.");
		}
	}

	public String getStrengthEdit() {
		if (courseModel.getObject().getStrength() == Courses.NOT_AVAILABLE)
			return UNAVAILABLE;
		return courseModel.getObject().getStrength().toString();
	}

	private IModel<Courses> courseModel;
	private boolean error = false;

	public static final String UNAVAILABLE = "N/A";
	private static final long serialVersionUID = 6086196556701565504L;
}
